﻿using System;
using System.Data.Common;
using System.Linq;

using Centido.Core;

namespace Centido.Management.ConsoleManager
{
    /// <summary>
    ///   A console command that lists all role security principals.
    /// </summary>
    internal class ListRolePrincipalsCommand : Command
    {
        /// <summary>
        ///   The role name parameter.
        /// </summary>
        public const string RoleNameParameter = "role";

        /// <summary>
        ///   The role name parameter.
        /// </summary>
        public const string RoleNameShortParameter = "r";

        /// <summary>
        ///   The all option parameter.
        /// </summary>
        public const string DisplayAllOptionParameter = "all";

        /// <summary>
        ///   The all option parameter (short name).
        /// </summary>
        public const string DisplayAllOptionShortParameter = "i";


        /// <summary>
        ///   Gets the console command name.
        /// </summary>
        public override string Name
        {
            get { return "listroleprincipals"; }
        }


        /// <summary>
        ///   Gets the console command description.
        /// </summary>
        public override string Description
        {
            get { return Messages.ListRolePrincipalsCommandDescription; }
        }

        
        /// <summary>
        ///   Gets the console command full description.
        /// </summary>
        public override string FullDescription
        {
            get { return Messages.ListRolePrincipalsCommandFullDescription; }
        }


        /// <summary>
        ///   Executes the console command.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="context"/> is null.</exception>
        public override void Execute(CommandExecutionContext context)
        {
            base.Execute(context);

            var domain = context.CurrentDomain;

            if (domain == null) return;

            // If the current user has no permission to perform this action
            if (!domain.CurrentUser.CanChangeSecurity)
            {
                Console.WriteLine(Messages.NeedCanChangeSecurityPermissionMessage);
                return;
            }

            try
            {
                // If the role name was specified
                if (context.ParameterValueIsNotEmpty(RoleNameParameter, RoleNameShortParameter))
                {
                    // The role name
                    var roleName = context.GetParameterValue(RoleNameParameter, RoleNameShortParameter);

                    // Trying to find the role
                    var role = domain.GetRole(roleName);

                    // If the role was not found
                    if (role == null)
                    {
                        Console.WriteLine(Messages.CannotFindRoleError, roleName);
                        return;
                    }

                    DisplayRolePrincipals(context, role);   
                }
                // If the role was not specified
                else
                {
                    // Enumerating roles
                    foreach (var role in domain.Roles.OrderBy(r => r.Name))
                    {
                        // If the all option was specified
                        if (context.GetParameterByName(DisplayAllOptionParameter, DisplayAllOptionShortParameter) != null
                            // ... and the role has the display name
                            && !string.IsNullOrEmpty(role.DisplayName))
                            Console.WriteLine("{0} ({1})", role.Name, role.DisplayName);
                        else
                            Console.WriteLine(role.Name);

                        DisplayRolePrincipals(context, role, displayOffset: true);

                        Console.WriteLine();
                    }
                }
            }
            catch (DbException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
            }
        }


        /// <summary>
        ///   Displays role security principals.
        /// </summary>
        /// <param name="context">The command execution context.</param>
        /// <param name="role">The security role.</param>
        /// <param name="displayOffset">The need to display the offset.</param>
        private static void DisplayRolePrincipals(CommandExecutionContext context,
            Role role, bool displayOffset = false)
        {
            // Enumerating role security principals
            foreach (var principal in role.Principals.OrderBy(p => p.Name))
            {
                // If the all option was specified
                if (context.GetParameterByName(DisplayAllOptionParameter, DisplayAllOptionShortParameter) != null
                    // ... and the principal has the display name
                    && !string.IsNullOrEmpty(principal.DisplayName))
                    Console.WriteLine("{0}{1} ({2})",
                        displayOffset ? "     " : string.Empty,
                        principal.Name,
                        principal.DisplayName);
                else
                    Console.WriteLine("{0}{1}",
                        displayOffset ? "     " : string.Empty,
                        principal.Name);
            }
        }
    }
}
